package Threads.Patterns;

import javafx.geometry.Pos;

import java.util.Hashtable;
import java.util.Map;
import java.util.Set;

//同步模式之保护性暂停
public class GuardedSuspension {
    public static void main(String[] args) throws InterruptedException {
        for (int i=0;i<3;i++)
            new people().start();

        Thread.sleep(1000);

        for (Integer id:Mailboxes.getIds())
            new Postman(id,"hello"+id).start();

    }

    //people
    public static class people extends Thread{
        @Override
        public void run() {
            GuardObject guardedObject = Mailboxes.createGuardedObject();
            System.out.println("开始收信 id:"+guardedObject.getId());
            String mail = (String)guardedObject.get(5000);
            System.out.println("收到信 id:"+guardedObject.getId()+" 内容："+mail);
        }
    }

    //postman
    public static class Postman extends Thread{
        private  int id;
        private  String mail;

        public Postman(int id,String mail){
            this.id=id;
            this.mail=mail;
        }

        @Override
        public void run() {
            GuardObject guardedObject = Mailboxes.getGuardedObject(id);
            System.out.println("送信：id："+id+"内容："+mail);
            guardedObject.put(mail);
        }

    }

    //解耦
    public static class Mailboxes{
        private static Map<Integer,GuardObject> boxes=new Hashtable<>();

        private static int id=1;

        //为每一个GuardObject产生不同id
        private static synchronized int generateId(){return id++;}

        public static GuardObject getGuardedObject(int id){return boxes.remove(id);}

        public static GuardObject createGuardedObject(){
            GuardObject go=new GuardObject(generateId());
            boxes.put(go.getId(),go);
            return go;
        }

        public static Set<Integer> getIds() {
            return boxes.keySet();
        }
    }

    //增加超时结果
    public static class GuardObject{
        private int id;

        public GuardObject(int id){this.id=id;}

        public int getId(){return id;}

        private Object response; //结果

        //produce the response
        public void put(Object response){
            synchronized (this){
                this.response=response;
                //唤醒等待获取的线程
                this.notifyAll();
            }
        }

        //get the response
        public Object get(long timeout){
            synchronized (this){
                long begin=System.currentTimeMillis();
                long passedTime=0;
                while (response==null){
                    //这种做法可以防止虚假唤醒后，等待时间变长，需要注意这个思想！

                    //计算该次循环需要等待的事件
                    long waitTime=timeout-passedTime;

                    //证明已经超过了最大等待事件，直接break
                    if (timeout-passedTime<=0)
                        break;

                    try{
                        this.wait(waitTime);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    //求实际已经经历的时间
                    passedTime=System.currentTimeMillis()-begin;
                }
                return response;
            }
        }

    }
}
